package com.clw.service.impl;

import com.clw.dataobject.Product;
import com.clw.dataobject.Sale;
import com.clw.dataobject.SaleDetail;
import com.clw.dto.SaleDTO;
import com.clw.enums.ResultEnum;
import com.clw.exception.SellException;
import com.clw.repository.ProductRepository;
import com.clw.repository.SaleDetailRepository;
import com.clw.repository.SaleRepository;
import com.clw.service.SaleService;
import com.clw.utils.DateUtils;
import com.clw.utils.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by Administrator on 2018-03-01.
 */
@Service
public class SaleServiceImpl implements SaleService{

    @Autowired
    private SaleRepository repository;

    @Autowired
    private SaleDetailRepository detailRepository;

    @Autowired
    private ProductRepository productRepository;

    @Override
    public Page<Sale> findPage(String saleNo, String buyerId, String startTime, String endTime, Pageable pageable) {
        return repository.findAll(getSpecification(saleNo,buyerId,startTime,endTime),pageable);
    }

    @Override
    public Long getSize(String saleNo, String buyerId, String startTime, String endTime) {
        return repository.count(getSpecification(saleNo,buyerId,startTime,endTime));
    }

    @Override
    public List<SaleDetail> getDetail(String saleNo) {
        return detailRepository.findAllBySaleNo(saleNo);
    }

    @Override
    public Sale findOne(Integer id) {
        return repository.findOne(id);
    }

    @Transactional
    @Override
    public SaleDTO add(SaleDTO dto) {
        Sale sale=new Sale();
        BeanUtils.copyProperties(dto,sale);
        sale.setCreateTime(new Date());
        sale.setStatus(0);
        Sale result=repository.save(sale);
        for (SaleDetail detail:dto.getDetails()){
            detail.setSaleNo(result.getSaleNo());
            detailRepository.save(detail);
        }
        return dto;
    }

    @Transactional
    @Override
    public SaleDTO update(SaleDTO dto) {
        List<SaleDetail> oldValueList=detailRepository.findAllBySaleNo(dto.getSaleNo());
        List<SaleDetail> newValueList=dto.getDetails();
        if (newValueList!=null&&newValueList.size()>0){
            for (SaleDetail oldValue:oldValueList){
                boolean isUpdate=false;
                for (SaleDetail newValue:newValueList){
                    if (oldValue.getId().equals(newValue.getId())){
                        newValue.setSaleNo(oldValue.getSaleNo());
                        detailRepository.save(newValue);
                        isUpdate=true;
                        break;
                    }
                }
                if (!isUpdate){
                    detailRepository.delete(oldValue);
                }
            }

            for (SaleDetail value:newValueList){
                if (StringUtils.isEmpty(value.getId())){
                    value.setSaleNo(dto.getSaleNo());
                    detailRepository.save(value);
                }
            }

        }
        Sale order=repository.findOne(dto.getId());
        BeanUtils.copyProperties(dto,order);
        repository.save(order);
        return dto;
    }

    @Transactional
    @Override
    public Sale del(Sale sale) {
        String saleNo=sale.getSaleNo();
        List<SaleDetail> details=detailRepository.findAllBySaleNo(saleNo);
        repository.delete(sale);
        for (SaleDetail detail:details){
            detailRepository.delete(detail);
        }
        return sale;
    }

    @Override
    public Sale save(Sale order) {
        return repository.save(order);
    }

    @Transactional
    @Override
    public Sale review(Sale order) {
        //查询订单明细
        String purNo=order.getSaleNo();
        List<SaleDetail> detailList=detailRepository.findAllBySaleNo(purNo);
        //寻找对应商品
        for (SaleDetail detail:detailList){
            Product product=productRepository.findOne(detail.getProductId());
            if (product==null){
                throw new SellException(ResultEnum.PRODUCT_NOT_FOUND);
            }
            Integer count=product.getCount()-detail.getCount();
            if (count<0){
                throw new SellException(ResultEnum.STOCK_NOT_ENOUGH);
            }
            product.setCount(count);
        }
        return repository.save(order);

    }

    @Override
    public List<Sale> getAllFinishOrder() {
        return repository.findAllByStatus(1);
    }

    private Specification<Sale> getSpecification(String saleNo, String buyerId, String startTime, String endTime){
        return new Specification<Sale>() {
            @Override
            public Predicate toPredicate(Root<Sale> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates=new ArrayList<>();
                if (StringUtils.isNotEmpty(saleNo)){
                    predicates.add(criteriaBuilder.like(root.get("saleNo"),"%"+saleNo+"%"));
                }
                if (StringUtils.isNotEmpty(buyerId)){
                    predicates.add(criteriaBuilder.equal(root.get("buyerId"),Integer.parseInt(buyerId)));
                }
                if (StringUtils.isNotEmpty(startTime)){
                    Date start= DateUtils.stringToDate(startTime);
                    predicates.add(criteriaBuilder.greaterThan(root.get("createTime"),start));
                }
                if (StringUtils.isNotEmpty(endTime)){
                    Date end=DateUtils.addDay(endTime,1);
                    predicates.add(criteriaBuilder.lessThan(root.get("createTime"),end));
                }
                return criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        };
    }
}
